package com.lzj.admin.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.lzj.admin.pojo.Goods;
import com.lzj.admin.mapper.GoodsMapper;
import com.lzj.admin.query.GoodsQuery;
import com.lzj.admin.service.ICustomerReturnListGoodsService;
import com.lzj.admin.service.IGoodsService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lzj.admin.service.IGoodsTypeService;
import com.lzj.admin.service.ISaleListGoodsService;
import com.lzj.admin.utils.AssertUtil;
import com.lzj.admin.utils.PageResultUtil;
import com.lzj.admin.utils.PinYinUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;

import static com.baomidou.mybatisplus.core.toolkit.ObjectUtils.isEmpty;

/**
 * <p>
 * 商品表 服务实现类
 * </p>
 *
 * @author luoyoumou
 * @date 2022-12-05
 */
@Service
public class GoodsServiceImpl extends ServiceImpl<GoodsMapper, Goods> implements IGoodsService {
    @Resource
    private IGoodsTypeService goodsTypeService;

    @Resource
    private ISaleListGoodsService saleListGoodsService;

    @Resource
    private ICustomerReturnListGoodsService customerReturnListGoodsService;

    @Override
    public Goods getGoodsInfoById(Integer gid) {
        return  this.baseMapper.getGoodsInfoById(gid);
    }

    @Override
    public Map<String, Object> stockList(GoodsQuery goodsQuery) {
        IPage<Goods> page = new Page<Goods>(goodsQuery.getPage(),goodsQuery.getLimit());
        if(null !=goodsQuery.getTypeId()){
            goodsQuery.setTypeIds(goodsTypeService.queryAllSubTypeIdsByTypeId(goodsQuery.getTypeId()));
        }
        if( null != goodsQuery.getTypeName()){
            goodsQuery.setTypeIds(goodsTypeService.queryAllSubTypeIdsByTypeId(goodsQuery.getTypeName()));
        }
        page =  this.baseMapper.queryGoodsByParams(page,goodsQuery);

        List<Goods> goodsList = page.getRecords();
        goodsList.forEach(g->{
            g.setSaleTotal(
                    saleListGoodsService.getSaleTotalByGoodsId(g.getId())-
                            customerReturnListGoodsService.getReturnTotalByGoodsId(g.getId())
            );
        });
        return PageResultUtil.getResult(page.getTotal(),goodsList);
    }

    @Override
    public Map<String, Object> goodsList(GoodsQuery goodsQuery) {
        IPage<Goods> page = new Page<Goods>(goodsQuery.getPage(),goodsQuery.getLimit());

        if(null != goodsQuery.getTypeId()){
            goodsQuery.setTypeIds(goodsTypeService.queryAllSubTypeIdsByTypeId(goodsQuery.getTypeId()));
        }
        if( null != goodsQuery.getTypeName()){
            goodsQuery.setTypeIds(goodsTypeService.queryAllSubTypeIdsByTypeId(goodsQuery.getTypeName()));
        }

        page = this.baseMapper.queryGoodsByParams(page,goodsQuery);
        return (Map<String, Object>) PageResultUtil.getResult(page.getTotal(),page.getRecords());
    }

    public String getGoodsCode(){
        String maxGoodsCode=this.baseMapper.selectOne(new QueryWrapper<Goods>().select("max(code) as code")).getCode();
        if(StringUtils.isNotEmpty(maxGoodsCode)){
            Integer code = Integer.valueOf(maxGoodsCode)+1;
            String codes = code.toString();
            int length = codes.length();
            for(int i = 4; i > length; i--){
                codes = "0"+codes;
            }
            return codes;
        } else {
            return "0001";
        }
    }

    /**
     * 商品信息 - 保存
     * 1. 参数校验
     *   商品名 类别 单位 非空； 类别 + 名称 无重复
     * 2. 设置商品唯一编码
     * 3. 其他参数设置
     *   默认设置库存 0
     *   商品状态 state：0 初始化状态；1 期初库存入仓库；2 有进货或者销售单据
     *   采购价格 0F
     *   isDel 0
     * @param goods
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
    public void saveGoods(Goods goods) {
        AssertUtil.isTrue(StringUtils.isBlank(goods.getName().trim()),"请指定商品名称！");
        AssertUtil.isTrue(null == goods.getTypeId(),"请指定商品类别！");
        AssertUtil.isTrue(isEmpty(goods.getUnit())||0 == goods.getUnit(),"请指定商品单位！");
        AssertUtil.isTrue(null != this.findGoodsByNameTypeId(goods.getName().trim(),goods.getTypeId()),"相同类别下，商品名冲突！");
        goods.setName(goods.getName().trim());
        goods.setCode(getGoodsCode());
        goods.setInventoryQuantity(0);// 库存 0
        // 如果配置默认值的话，最好把下面这些字段从页面上屏蔽 待解决
        if(null == goods.getPurchasingPrice()){
            goods.setPurchasingPrice(0F); // 采购价 0
        }
        if(null == goods.getSellingPrice()){
            goods.setSellingPrice(0F); // 销售价 0
        }
        if(null == goods.getMinNum()){
            goods.setMinNum(1); // 最低库存
        }
        goods.setState(0);            // 初始状态 0
        goods.setLastPurchasingPrice(0F);
        goods.setIsDel(0);            // 有效(非删除)状态
        goods.setFpyName(PinYinUtil.getFirstSpell(goods.getName()));
        AssertUtil.isTrue(!(this.save(goods)),"商品记录添加失败！");
    }

    /**
     * 判断相同商品类别下，商品名是否已存在
     * @param name
     * @param typeId
     * @return
     */
    @Override
    public Object findGoodsByNameTypeId(String name, Integer typeId) {
        return this.getOne(new QueryWrapper<Goods>().eq("is_del",0).eq("name",name).eq("type_id",typeId));
    }

    /**
     * 判断相同商品类别下，商品名是否已存在，排除指定的 商品Id
     * @param name
     * @param typeId
     * @param goodsId
     * @return
     */
    public Object findGoodsByNameTypeId(String name, Integer typeId,Integer goodsId) {
        return this.getOne(new QueryWrapper<Goods>().eq("is_del",0).notIn("id",goodsId).eq("name",name).eq("type_id",typeId));
    }

    /**
     * 商品信息 - 更新
     * 1. 参数校验
     *   商品名 类别 单位 非空
     * 2. 已产生单据的商品，不允许修改名称 ( 因为单据里面的 商品名称 & 商品型号 是写死在里面的(没有关联 商品信息表)，如果再次修改的话，将引起混乱 )
     * @param goods
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
    public void updateGoods(Goods goods) {
        AssertUtil.isTrue(null == this.getById(goods.getId()),"请选择商品记录！");
        AssertUtil.isTrue(StringUtils.isBlank(goods.getName().trim()),"请指定商品名称！");
        AssertUtil.isTrue(null == goods.getTypeId(),"请指定商品类别！");
        AssertUtil.isTrue(null != this.findGoodsByNameTypeId(goods.getName().trim(),goods.getTypeId(),goods.getId()),"相同类别下，商品名冲突！");

        Goods tmpGoods = this.getGoodsInfoById(goods.getId());
        AssertUtil.isTrue(null == tmpGoods,"指定商品不存在！");
        AssertUtil.isTrue(tmpGoods.getId() == goods.getId() && tmpGoods.getState() == 2 && ( !(tmpGoods.getName().equals(goods.getName().trim())) || !(tmpGoods.getModel().equals(goods.getModel().trim()))),"该商品已产生订单，不再允许修改商品名称或型号信息！");

        AssertUtil.isTrue(isEmpty(goods.getUnit())||0 == goods.getUnit(),"请指定商品单位！");
        goods.setName(goods.getName().trim());
        goods.setModel(goods.getModel().trim());
        goods.setFpyName(PinYinUtil.getFirstSpell(goods.getName().trim()));
        AssertUtil.isTrue(!(this.updateById(goods)),"商品记录更新失败！");
    }

    /**
     * 商品信息 - 删除
     * 1. 删除记录必须存在
     * 2. 不可删除的条件：
     *      如果商品已经期初入库 不可删除
     *      商品已经发生单据 不能删除
     * 3. 执行更新 isDel 0->1
     * @param id
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
    public void deleteGoods(Integer id) {
        Goods goods = this.getById(id);
        AssertUtil.isTrue(null == goods,"待删除的商品记录不存在！");
        AssertUtil.isTrue(goods.getState() == 1, "该商品已期初入库，不能删除！");
        AssertUtil.isTrue(goods.getState() == 2, "该商品已有单据，不能删除！");
        goods.setIsDel(1);
        AssertUtil.isTrue(!(this.updateById(goods)),"商品记录删除失败！");
    }

    /**
     * 商品信息 - 入库：设置商品库存，成本价
     * 商品库存量>0
     * 商品成本价>0
     * 更新商品状态为 1 setState(1)
     * @param goods
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
    public void updateStock(Goods goods) {
        Goods tempGoods = this.getById(goods.getId());
        AssertUtil.isTrue(null == tempGoods,"待更新的商品记录不存在！");
        AssertUtil.isTrue(goods.getInventoryQuantity()<=0,"库存量必须>0");
        AssertUtil.isTrue(goods.getPurchasingPrice()<=0,"成本价必须>0");
        goods.setState(1);
        AssertUtil.isTrue(!(this.updateById(goods)),"商品记录更新失败！");
    }


    /**
     * 商品信息 - 清仓：即设置商品库存为 0，state=0
     * @param id
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
    public void deleteStock(Integer id) {
        Goods goods = this.getById(id);
        AssertUtil.isTrue(null == goods,"待清空库存的商品记录不存在！");
        AssertUtil.isTrue( 2 == goods.getState(),"该商品已产生单据，不能清空库存！");
        goods.setInventoryQuantity(0);
        goods.setState(0);
        AssertUtil.isTrue(!(this.updateById(goods)),"商品库存信息已清空！");
    }

}
